/**
 * 指针和数组 https://www.bilibili.com/video/BV1vs411n7TH?p=65
 */
#include <stdio.h>

void pointer_array_same();
void pointer_array_difference();
void pointer_array_edit();

int main() {
    //1.指针和数组 的相同点
    pointer_array_same();
    //2.指针&数组 的不同点
    pointer_array_difference();
    //3.指针&数组 修改
    pointer_array_edit();
    return 0;
}

/**
 * 1.指针&数组 的相同点
 *   数组包含的所有元素在内存中都有地址.
 *   p[i]                : 取数组中第1个元素
 *   *p                  : 取指针指向的数组中第1元素
 *   *(arr + i), *(p + i): (arr + 1 和 p + 1 都是指针类型 + 1), [指针类型 + 1 = 内存地址 + sizeof(数据类型)]
 *   p++                 : 指向数组中 下一个数据类型的 地址
 *                         指针的 加/减 运算, 和指针的类型有关, 和指向的数据类型无关
 *   p - arr = 10        : 2个指针相减 = 2个指针的偏移量
 */
void pointer_array_same() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int *p = arr;               //指针指向数组首地址
    for (int i = 0; i < 10; ++i) {
        printf("p[%d] = %d\n", i, p[i]); //用指针打印
    }
    printf("第1个元素*p = %d\n", *p); //1, 打印第1个元素

    //内存地址 + 1 = 内存地址 + sizeof(数据类型)
    for (int i = 0; i < 10; ++i) {
        //arr + 0 = 0x6422156,  p + 0 = 0x6422156,  *(arr + 0) = 1,  *(p + 0) = 1
        printf("arr + %d = 0x%d,  p + %d = 0x%d,  *(arr + %d) = %d,  *(p + %d) = %d\n", i, arr + i, i, p + i, i, *(arr + i), i, *(p + i));
    }

    for (int i = 0; i < 10; ++i) {
        printf("*p++ = %d\n", *p++); //*p++ = 1
    }

    /**
     * 2个指针相减 = 2个指针的偏移量.
     * ∵ p++ 经过了10次, ∴和arr地址有10的距离
     */
    unsigned long step = p - arr;
    printf("p - arr = %ld\n", step); //10
}

/**
 * 2.指针&数组 的不同点
 */
void pointer_array_difference() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int *p = arr;
    printf("sizeof(p) = %d\n", sizeof(p));     //4
    printf("sizeof(arr) = %d\n", sizeof(arr)); //40
}

/**
 * https://www.bilibili.com/video/BV1vs411n7TH?p=77
 * 3.指针&数组 修改
 * @see 14.pointer.c#const_pointer()
 */
void pointer_array_edit() {
    char ch1[] = "Hello";
    char ch2[] = "World";
    //1.常量指针, const 在*左边, 修饰char, ∴char值不能修改.  但可以修改指针变量的值
    const char *p = ch1;
//    *p = 'm';             //不能修改, 编译不过
//    p[1] = 'm';
//    *(p + 1) = 'm';       //同上

    p = ch2;                //可以修改指针变量的值
    printf("p = %s\n", p);  //World

    //2.指针常量, const 在*右侧, 修饰的p2, 所以p2不能修改
    char* const p2 = ch1;
    *p2 = 'm';
//    p2 = ch2;              //不可修改
    printf("p2 = %s\n", p2); //mello

    //3.指向常量的常量指针
    const char* const p3 = ch1;
//    *p3 = 'm';            //不可更改
//    p3 = ch2;             //↑

    //通过2级指针修改p3的值
    char** pp = &p3;
    *pp = ch2;
    *(*pp + 2) = 'o';       //将r改成o
    printf("p3 = %s\n", p3);//Woold
}
